package yui.comn.hub.extension.controller;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.baomidou.mybatisplus.core.metadata.IPage;

import yui.comn.hub.data.parser.HubDataToMapParser;
import yui.comn.hub.extension.config.HubExtensionProperties;
import yui.comn.hub.extension.model.CdNmModel;
import yui.comn.hub.extension.model.VodWrapper;
import yui.comn.hub.extension.poi.ExcelData;
import yui.comn.hub.extension.poi.ExportExcelUtils;
import yui.comn.hub.extension.poi.ImportExcelUtils;
import yui.comn.hub.extension.utils.GenerateVodWrapper;
import yui.comn.hub.extension.utils.GsonUtils;
import yui.comn.hub.model.HubXmlColumn;
import yui.comn.hub.utils.DateUtils;
import yui.comn.hub.xml.parser.HubXmlCache;
import yui.comn.mybatisx.core.conditions.query.FindWrapper;
import yui.comn.mybatisx.core.toolkit.CollStrUtils;
import yui.comn.mybatisx.extension.conditions.GenerateWrapper;
import yui.comn.mybatisx.extension.conditions.clauses.QueryClause;
import yui.comn.mybatisx.extension.utils.QueryClauseUtils;

/**
 * 控制器的基类，将公共方法写在这个类中
 * 
 * @author yi.yuy
 */

public abstract class Controller {
    protected final Logger log = LoggerFactory.getLogger(getClass());
    
    // @Value("${hub-link.extension.openHeader: true}")  //默认开启查询接口返回字段含义
    // private boolean isOpenHeader = true;
    // @Value("${hub-link.extension.titleRowNum: 0}")
    // private boolean titleRowNum = true;
    // @Value("${hub-link.extension.bodyRowNum: 1}")
    // private boolean bodyRowNum = true;
    @Autowired
	private HubExtensionProperties properties;
    
    protected static final String QUERY = "QUERY";
    
    protected static final String LIST = "LIST";
    protected static final String INFO = "INFO";
    protected static final String EXPT = "EXPT";
    protected static final String IMPT = "IMPT";
    protected static final String IMPT_ERR = "IMPT_ERR";
    protected static final String DTL = "DTL";
    
    protected static final String ITEMS = "list";
    
    protected static final int EXPORT_MAX_ROW = 20000;
    
    protected static final int SUCCESS = 0;
    protected static final String SUCCESS_MSG = "成功";
    protected static final String FAILURE_MSG = "失败";
    protected static final int FAILURE = 400;
    
    
    
    /********************************************结果解析*****************************************************/
    public Object ok() {
        return ok(SUCCESS_MSG);
    }
    
    public Object ok(String msg) {
        return buildSuccess(SUCCESS_MSG);
    }
    
    public Object err() {
        return buildFailure(FAILURE_MSG);
    }
    
    public Object err(String msg) {
        return buildFailure(msg);
    }
    
    public Object build(Object obj) {
        if (obj instanceof IPage) {
            return buildPage((IPage<?>) obj);
        } else if (obj instanceof Collection) {
            return buildList((Collection<?>) obj);
        } else {
            return buildObj(obj);
        }
    }
    
    public Object build(Object obj, String gridName) {
        if (obj instanceof IPage) {
            return buildPage((IPage<?>) obj, gridName);
        } else if (obj instanceof Collection) {
            return buildList((Collection<?>) obj, gridName);
        } else {
            return buildObj(obj, gridName);
        }
    }
    
    public Object buildSuccess() {
        return buildSuccess(SUCCESS_MSG);
    }
    
    public Object buildSuccess(String msg) {
        return buildResult(SUCCESS, null, null, msg, null);
    }
    
    public Object buildFailure(String message) {
        return buildResult(FAILURE, null, null, message, null);
    }
    
    public Object buildFailure(int code, String message) {
        return buildResult(code, null, null, message, null);
    }
    
    protected Object buildObj(Object obj) {
        return buildResult(SUCCESS, obj, null, null, null);
    }
    
    public Object buildObj(Object obj, String gridName) {
        Map<String, Object> mapData = HubDataToMapParser.getInstance().toMapByObj(this.getClass(), gridName, obj);
        return buildResult(SUCCESS, mapData, null, null, gridName);
    }
    
    public Object buildList(Collection<?> list) {
        Map<String, Collection<?>> mapData = getMapData(list);
        return buildResult(SUCCESS, mapData, null, null, null);
    }
    
    public Object buildList(Collection<?> list, String gridName) {
        List<Map<String, Object>> mapList = HubDataToMapParser.getInstance().toMapListByObjList(this.getClass(), gridName, list);
        Map<String, Collection<?>> mapData = getMapData(mapList);
        return buildResult(SUCCESS, mapData, null, null, gridName);
    }
    
    public Object buildPage(IPage<?> page) {
        Map<String, Collection<?>> mapData = getMapData(page.getRecords());
        return buildResult(SUCCESS, mapData, page, null, null);
    }
    
    public Object buildPage(IPage<?> page, String gridName) {
        List<Map<String, Object>> list = HubDataToMapParser.getInstance().toMapListByObjList(this.getClass(), gridName, page.getRecords());
        Map<String, Collection<?>> mapData = getMapData(list);
        return buildResult(SUCCESS, mapData, page, null, gridName);
    }
    
    protected Object buildResult(int code, Object data, IPage<?> page, String msg, String gridName) {
        Map<String, Object> root = new LinkedHashMap<String, Object>();
        root.put("code", code);
        if (null != msg) {
            root.put("msg", msg);
        }
        if (null != gridName && properties.isOpenHeader()) {
            root.put("header", HubXmlCache.getInstance().toGridKvMap(this.getClass(), gridName));
        }
        if (null != data) {
            root.put("data", data);
        }
        if (null != page) {
            Map<String, Object> pagination = new HashMap<String, Object>();
            pagination.put("total", page.getTotal());
            pagination.put("pageSize", page.getSize());
            pagination.put("pageNum", page.getCurrent());
            root.put("page", pagination);
        }
        return root;
    }
    
    private Map<String, Collection<?>> getMapData(Collection<?> list) {
        Map<String, Collection<?>> map = new HashMap<>();
        map.put(ITEMS, list);
        return map;
    }
    /********************************************Excel导入******************************************************/
    protected <T> List<T> importExcel(HttpServletRequest request, Class<T> clazz, String gridName) {
        MultipartHttpServletRequest mhs = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> multiFileMap = mhs.getFileMap();
        MultipartFile file = multiFileMap.values().iterator().next();
        return importExcel(file, clazz, gridName, properties.getTitleRowNum(), properties.getBodyRowNum());
    }
    
    protected <T> List<T> importExcel(HttpServletRequest request, Class<T> clazz, 
    		String gridName, Integer titleRowNum, Integer bodyRowNum) {
    	MultipartHttpServletRequest mhs = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> multiFileMap = mhs.getFileMap();
        MultipartFile file = multiFileMap.values().iterator().next();
        return importExcel(file, clazz, gridName, titleRowNum, bodyRowNum);
    }
    
    protected <T> List<T> importExcel(MultipartFile file, Class<T> clazz, 
    		String gridName, Integer titleRowNum, Integer bodyRowNum) {
        List<HubXmlColumn> columns = HubXmlCache.getInstance().toGridList(this.getClass(), gridName);
        return importExcel(file, clazz, columns, titleRowNum, bodyRowNum);
        
    }
    
    protected <T> List<T> importExcel(MultipartFile file, Class<T> clazz, 
    		List<HubXmlColumn> columns, int titleRowNum, int bodyRowNum) {
    	return ImportExcelUtils.readExcel(file, clazz, columns, titleRowNum, bodyRowNum);
    }
    
    /********************************************Excel导出******************************************************/
    protected void exportExcelDemo(HttpServletResponse response, List<?> list, String gridName) {
        String simpleName = StringUtils.remove(this.getClass().getSimpleName(), "Controller");
        String fileName = simpleName + "-demo-" + DateUtils.format(DateUtils.DATA_FORMAT) + ".xlsx";
        exportExcel(response, list, fileName, gridName, null);
    }
    
    protected List<CdNmModel> exportField(String gridName) {
        List<CdNmModel> list = new ArrayList<>();
        List<HubXmlColumn> columns = HubXmlCache.getInstance().toGridList(this.getClass(), gridName);
        for (HubXmlColumn col : columns) {
            list.add(new CdNmModel(col.getName(), col.getDescr()));
        }
        return list;
    }
    
    protected void exportExcel(HttpServletResponse response, List<?> list, String gridName) {
        exportExcel(response, list, gridName, null);
    }
    
    protected void exportExcel(HttpServletResponse response, List<?> list, String gridName, String query) {
        String simpleName = StringUtils.remove(this.getClass().getSimpleName(), "Controller");
        String fileName = simpleName + "-" + DateUtils.format(DateUtils.DATA_FORMAT) + ".xlsx";
        exportExcel(response, list, fileName, gridName, query);
    }
    
    protected void exportExcel(HttpServletResponse response, List<?> list, String fileName, String gridName, String query) {
        List<String> select = null;
        if (StringUtils.isNotBlank(query)) {
            QueryClause queryClause = GsonUtils.JsonStr2JavaBean(query, QueryClause.class);
            if (null != queryClause.getS()) {
                select = CollStrUtils.toStrList(queryClause.getS().getV());
            }
        }
        
        List<HubXmlColumn> allColumns = HubXmlCache.getInstance().toGridList(this.getClass(), gridName);
        List<HubXmlColumn> columns = new ArrayList<>();
        for (HubXmlColumn col : allColumns) {
            if (null == select || select.contains(col.getName())) {
                columns.add(col);
            }
        }
        
        ExcelData data = new ExcelData();
        //excel标题设置
        List<String> titles = new ArrayList<>();
        for (HubXmlColumn col : columns) {
            titles.add(col.getDescr());
        }
        data.setTitles(titles);
        //excel值赋值
        List<Map<String, Object>> resultSet = HubDataToMapParser.getInstance().toMapListByObjList(this.getClass(), gridName, list);
        List<List<Object>> rows = new ArrayList<>();
        for (Map<String, Object> map : resultSet) {
            List<Object> row = new ArrayList<>();
            for (HubXmlColumn col : columns) {
                row.add(map.get(col.getName()));
            }
            rows.add(row);
        }
        data.setRows(rows);
        exportExcel(response, fileName, data);
    }
    
    protected void exportExcel(HttpServletResponse response, String fileName, ExcelData data) {
    	ExportExcelUtils.exportExcel(response, fileName, data);
    }
    
    /********************************************设置参数*****************************************************/
    protected <V> FindWrapper<V> getWrapper(String query, Class<V> entityClass) {
        return getWrapper(query, entityClass, QUERY, LIST);
    }
    
    protected <V> FindWrapper<V> getWrapper(String query, Class<V> entityClass, String queryMapperName) {
    	return getWrapper(query, entityClass, queryMapperName, LIST);
    }
    
    protected <V> FindWrapper<V> getWrapper(String query, Class<V> entityClass, 
            String queryMapperName, String selectMapperName) {
    	if (StringUtils.isBlank(query)) {
            return new FindWrapper<>();
        }
        return getWrapper(getQueryClause(query), entityClass, queryMapperName, selectMapperName);
    }
    
    protected <V> FindWrapper<V> getWrapper(QueryClause queryClause, Class<V> entityClass) {
        return getWrapper(queryClause, entityClass, QUERY, LIST);
    }
    
    protected <V> FindWrapper<V> getWrapper(QueryClause queryClause, Class<V> entityClass, String queryMapperName) {
    	return getWrapper(queryClause, entityClass, queryMapperName, LIST);
    }
    
    protected <V> FindWrapper<V> getWrapper(QueryClause queryClause, Class<V> entityClass, 
            String queryMapperName, String selectMapperName) {
        FindWrapper<V> wrapper = new FindWrapper<>();
        
        Map<String, String> queryMapper = HubXmlCache.getInstance().toSearch(getClass(), queryMapperName);
        
        Map<String, String> fieldMapper = null;
        if (null != queryClause.getS() && null != queryClause.getS().getV()) {
        	fieldMapper = HubXmlCache.getInstance().toGridFieldKvList(getClass(), selectMapperName);
        }
        
        GenerateWrapper.wrapperHandle(wrapper, queryClause, queryMapper, fieldMapper);
        
        return wrapper;
    }
    
    protected QueryClause getQueryClause(String query) {
        if (StringUtils.isBlank(query)) {
            return new QueryClause();
        }
        return QueryClauseUtils.JsonStr2JavaBean(query);
    }
    
    protected VodWrapper getVodWrapper(String query) {
        if (StringUtils.isBlank(query)) {
            return new VodWrapper();
        }
        VodWrapper wrapper = new VodWrapper();
        QueryClause queryClause = GsonUtils.JsonStr2JavaBean(query, QueryClause.class);
        GenerateVodWrapper.wrapperHandle(wrapper, queryClause);
        return wrapper;
    }
    
}
